区块链学习笔记之paradigm-CTF babysandbox
这个是去安全客翻zbr文章的时候看见的题,因为刚玩,还是想着多搞点题找点感觉
合约代码
BabySandbox.sol
1 | pragma solidity 0.7.0; |
Setup.sol
1 | pragma solidity 0.7.0; |
解题目标大概就是让sandbox这个合约的字节码size为0,就是让这个合约自毁叭。
那么看到这个BabySandbox里,应该是要用到里头的delegatecall,让它调用一下selfdestruct就可以了
但是首先,想要进这个delegatecall,需要满足条件eq(caller(), address()),
于是看到下面有一个
1 | if iszero(staticcall(0x4000, address(), 0, calldatasize(), 0, 0)) { |
他会合约自己进行一个staticcall【address() 就是 this.address】
类似于把你的calldata【此时你的calldata应该是 函数选择器为 run,参数为code 的 字节码】放进一个沙箱去执行,看你这个calldata有没有改变状态,有就revert了。要是没有,往下走,这儿就有一个
1 | call(0x4000, address(), 0, 0, calldatasize(), 0, 0) |
这个区别于staticcall他就是可以改变状态了。
所以我们就是要把selfdestruct塞到这个里面去。
但是显然selfdestruct是会改变合约状态的,这样在前面就被revert了。怎么绕呢?
我们想让BabySandbox执行我们合约的时候,staticcall能过,call又能调用到selfdestruct,所以我们的合约是需要能够检查到是被staticcall调用了,还是被call调用了这样一个功能。
在这篇wp提到,
既然不会整个revert,我们可以再部署一个被call时会改变状态(自毁啊,事件啥的)的合约,为了区别一下,这个合约就叫状态会改变合约,然后我们要传给BabySandbox的为瞒天过海合约,
我们的瞒天过海合约被call时,就call一下状态会改变合约,看一下返回值,如果返回0,说明状态修改失败,此时是staticcall,我们瞒天过海合约啥也不做,此时对于调用瞒天过海合约的staticcall来说,我们的瞒天过海合约正常执行了,虽然没返回什么东西,但也没报错啊【老实人.jpg】,于是返回一个1,就过了iszero了。
然后BabySandbox就走到call了,当call我们的瞒天过海合约的时候,瞒天过海合约又call一下状态会改变合约,这个时候状态应该修改成功,我们的瞒天过海合约收到一个1,然后瞒天过海合约就给BabySandbox调用一个selfdestruct。
参考https://medium.com/furucombo/sharing-some-paradigm-ctf-solutions-befac01800e3
具体步骤就是先部署一个状态会改变合约(被call的时候会触发一个事件)
1 | pragma solidity 0.7.0; |
这个合约部署好了之后,拿到他的地址(我这里是0xcD6a42782d230D7c13A74ddec5dD140e55499Df9),硬编码到我们的瞒天过海合约里头
1 | pragma solidity 0.7.0; |
然后把我们的瞒天过海合约部署的地址传给BabySandbox就好了。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可联系QQ 643713081,也可以邮件至 643713081@qq.com
文章标题:区块链学习笔记之paradigm-CTF babysandbox
文章字数:981
本文作者:Van1sh
发布时间:2022-02-11, 16:22:00
最后更新:2022-02-11, 17:07:40
原始链接:http://jayxv.github.io/2022/02/11/区块链学习笔记之paradigm-CTF babysandbox/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。